package cn.tedu.zookeeper;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class ZookeeperDemo1 {
    private ZooKeeper zooKeeper;

    /**
     * 测试连接自己的虚拟机
     */
    final private String ipAndPort = "mycentos8:2181";

    @Before
    public void connect() throws IOException, InterruptedException {
        // String connectString - 连接地址 + 端口号
        // int sessionTimeout - 连接会话超时时间
        // Watcher watcher - 用于监控这个连接是否建立
        // Zookeeper底层利用Netty去建立连接
        // Netty是NIO的框架, Netty提供的是一个异步非阻塞的连接
        // 非阻塞: 无论是否连接上, 都会继续往下执行
        // 这个过程中, 存在@Test这个测试线程以及Zookeeper的连接和监控进程
        // 测试线程有可能会先抢占执行, 导致连接线程还没有执行完, 测试线程就先结束了
        // 需要等待连接线程结束，测试线程才能结束
        CountDownLatch countDownLatch = new CountDownLatch(1);
        zooKeeper = new ZooKeeper(
                ipAndPort,
                5000,//单位默认是毫秒, 现在阶段要求这个值在4000到40000之间
                new Watcher() {
                    @Override
                    public void process(WatchedEvent watchedEvent) {
                        // 判断连接是否建立, 将监控的事件封装成WatchedEvent对象
                        if (watchedEvent.getState() == Event.KeeperState.SyncConnected)
                            System.out.println("连接成功");
                        countDownLatch.countDown();
                    }

                    ;
                }
        );
        countDownLatch.await();
        System.out.println("运行完成");
    }

    /**
     * 创建节点
     */
    @Test
    public void createNode() throws KeeperException, InterruptedException {
        // path - 节点路径
        // data - 数据
        // acl - 权限策略
        // createMode - 创建模式 - 节点类型
        // 返回值表示的节点路径
        String path = zooKeeper.create("/log", "log servers".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
        System.out.println(path);
    }

    /**
     * 删除节点
     */
    @Test
    public void deleteNode() throws InterruptedException, KeeperException {
        // path - 节点路径
        // version - 数据版本
        // 在删除的时候，会校验数据版本是否一致，如果一致才能删除
        // 如果version的值是-1，那么删除的时候就会忽略版本校验
        zooKeeper.delete("/log", -1);
    }

    /**
     * 修改节点的数据
     */
    @Test
    public void changeData() throws InterruptedException, KeeperException {
        // 返回值表示节点信息
        Stat stat = zooKeeper.setData("/log", "logs".getBytes(), -1);
        System.out.println(stat);
    }

    /**
     * 获取节点数据
     */
    @Test
    public void getData() throws InterruptedException, KeeperException {
        // 第三个参数表示节点信息，如果需要这个节点的信息，需要创建一个Stat对象来接收；如果不需要节点信息，可以给null
        // 返回值是数据
        Stat stat = new Stat();
        byte[] data = zooKeeper.getData("/log", null, stat);
        System.out.println(stat);
        System.out.println(new String(data));
    }

    /**
     * 获取子节点
     */
    @Test
    public void getChildren() throws InterruptedException, KeeperException {
        // 将子节点的路径名放入List集合返回
        List<String> paths = zooKeeper.getChildren("/", null);
        for (String path : paths)
            System.out.println(path);
    }

    /**
     * 判断节点是否存在
     */
    @Test
    public void exists() throws InterruptedException, KeeperException {
        // 返回值表示的是节点信息
        // 如果节点存在，则返回该节点的节点信息；如果不存在，返回null
        Stat stat = zooKeeper.exists("/tmp", null);
        System.out.println(stat);
    }
}
